package org.squabble.dao;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.squabble.domain.Account;

@Repository
public class AccountDAOImpl extends AbstractHibernateDAO<Account> implements
		AccountDAO {

	private final Log log = LogFactory.getLog(this.getClass());

	@Autowired
	public AccountDAOImpl(SessionFactory sessionFactory) {
		super(Account.class, sessionFactory);
	}

	public Account findBy(String field, String value) {
		return this.findBy(field, value, true);
	}

	public Account findBy(String field, String value, boolean caseSensitive) {
		log.debug("Searching for [" + value + "] in field [" + field + "]");
		Criteria criteria = criteria();
		if (!caseSensitive) {
			criteria.add(Restrictions.ilike(field, value));
		} else {
			criteria.add(Restrictions.like(field, value));
		}
		return uniqueResult(criteria);
	}

	public Account createAccount(Account account) {
		log.info("Creating account: " + account.toString());
		Long accountId = (Long) currentSession().save(account);
		account = get(accountId);
		return account;
	}

	public Account updateAccount(Account account) {
		currentSession().update(account);
		return getAccount(account.getId());
	}

	public Account getAccount(Long accountId) {
		return get(accountId);
	}

	@Override
	public List<Account> searchAccounts(String name, String email,
			Long privilegeId, MatchMode matchMode) {
		Criteria criteria = criteria();
		if (StringUtils.isNotBlank(name)) {
			criteria.add(Restrictions.ilike("name", name, matchMode));
		}
		if (StringUtils.isNotBlank(email)) {
			criteria.add(Restrictions.ilike("email", email, matchMode));
		}
		if (privilegeId != null) {
			criteria.createAlias("privileges", "p");
			criteria.add(Restrictions.eq("p.id", privilegeId));
		}
		criteria.addOrder(Order.asc("name"));
		List<Account> accounts = list(criteria);
		return accounts;
	}

	@Override
	public List<Account> findAccounts(Order orderBy, Integer limit) {
		Criteria criteria = criteria();
		criteria.addOrder(orderBy);
		if (limit != null) {
			criteria.setFetchSize(limit);
		}
		List<Account> accounts = list(criteria);
		log.debug("Returning " + accounts.size() + " accounts");
		return accounts;
	}

	@Override
	public List<Account> list() {
		Set<Account> set = new HashSet<Account>(this.all());
		return new ArrayList<Account>(set);
	}

}
